package com.agent.auth.service;

import com.agent.auth.entity.UserSession;
import com.agent.auth.mapper.UserSessionMapper;
import com.agent.common.entity.TokenPair;
import com.agent.common.entity.UserContext;
import com.agent.common.exception.AuthenticationException;
import com.agent.common.result.ApiResponse;
import com.agent.common.result.ResultCode;
import com.agent.common.utils.IdGenerator;
import com.agent.common.utils.JwtUtils;
import com.agent.user.api.feign.UserFeignClient;
import com.agent.user.api.resp.UserResp;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Collections;

/**
 * Google认证服务
 * @author Jeff_Wan
 * @description 处理Google OAuth2认证流程
 */
@Service
@RequiredArgsConstructor
public class GoogleAuthService {

    private final RestTemplate restTemplate;
    private final UserFeignClient userFeignClient;
    private final JwtUtils jwtUtils;
    private final UserSessionMapper userSessionMapper;

    @Value("${google.client-id}")
    private String clientId;

    @Value("${google.client-secret}")
    private String clientSecret;

    @Value("${google.redirect-uri}")
    private String redirectUri;

    @Value("${google.token-uri}")
    private String tokenUri;

    @Value("${google.user-info-uri}")
    private String userInfoUri;

    /**
     * 处理Google OAuth2回调
     * @param code 授权码
     * @return JWT访问令牌
     */
    public TokenPair handleGoogleCallback(String code) {
        // 1. 使用授权码获取访问令牌
        String accessToken = exchangeCodeForAccessToken(code);

        // 2. 使用访问令牌获取用户信息
        GoogleUserInfo userInfo = getUserInfo(accessToken);

        // 3. 创建或更新用户
        UserResp user = createOrUpdateUser(userInfo);

        // 4. 生成JWT令牌
        return generateJwtToken(user);
    }

    private String exchangeCodeForAccessToken(String code) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));

        String requestBody = String.format(
                "code=%s&client_id=%s&client_secret=%s&redirect_uri=%s&grant_type=authorization_code",
                code, clientId, clientSecret, redirectUri);

        HttpEntity<String> request = new HttpEntity<>(requestBody, headers);
        ResponseEntity<GoogleTokenResponse> response = restTemplate.postForEntity(
                tokenUri, request, GoogleTokenResponse.class);

        if (response.getStatusCode() != HttpStatus.OK || response.getBody() == null) {
            throw new AuthenticationException(ResultCode.INVALID_CREDENTIALS, "Failed to exchange code for access token");
        }

        return response.getBody().getAccessToken();
    }

    private GoogleUserInfo getUserInfo(String accessToken) {
        HttpHeaders headers = new HttpHeaders();
        headers.setBearerAuth(accessToken);

        HttpEntity<String> entity = new HttpEntity<>(headers);
        ResponseEntity<GoogleUserInfo> response = restTemplate.exchange(
                userInfoUri, HttpMethod.GET, entity, GoogleUserInfo.class);

        if (response.getStatusCode() != HttpStatus.OK || response.getBody() == null) {
            throw new AuthenticationException(ResultCode.INVALID_CREDENTIALS, "Failed to get user info from Google");
        }

        return response.getBody();
    }

    private UserResp createOrUpdateUser(GoogleUserInfo userInfo) {
        ApiResponse<UserResp> response = userFeignClient.createOrUpdateByGoogleId(
                userInfo.getId(),
                userInfo.getEmail(),
                userInfo.getName(),
                userInfo.getPicture());

        if (response.getCode() != ResultCode.SUCCESS.getCode() || response.getData() == null) {
            throw new AuthenticationException(ResultCode.USER_NOT_EXIST, "Failed to create or update user");
        }

        return response.getData();
    }

    private TokenPair generateJwtToken(UserResp user) {
        UserContext userContext = new UserContext();
        userContext.setUserId(user.getId());
        userContext.setUsername(user.getUsername());
        userContext.setEmail(user.getEmail());
        userContext.setAvatarUrl(user.getAvatarUrl());
        userContext.setMembershipType(user.getMembershipType()); // 默认为免费用户

        TokenPair tokenPair = jwtUtils.generateTokenPair(userContext);

        // 创建会话记录
        UserSession session = new UserSession();
        session.setId(IdGenerator.getInstance().nextId());
        session.setUserId(userContext.getUserId());
        session.setSessionToken(tokenPair.getAccessToken());
        session.setRefreshToken(tokenPair.getRefreshToken());
        session.setExpiresAt(LocalDateTime.now().plus(30, ChronoUnit.MINUTES));
        session.setRefreshExpiresAt(LocalDateTime.now().plus(7, ChronoUnit.DAYS));
        session.setCreatedAt(LocalDateTime.now());
        session.setLastAccessedAt(LocalDateTime.now());
        session.setIsActive(true);
        userSessionMapper.insert(session);

        return tokenPair;
    }

    // Google令牌响应DTO
    @Data
    private static class GoogleTokenResponse {
        private String access_token;
        private String token_type;
        private int expires_in;
        private String refresh_token;
        private String scope;

        public String getAccessToken() {
            return access_token;
        }
    }

    // Google用户信息DTO
    @Data
    private static class GoogleUserInfo {
        private String id;
        private String email;
        private String name;
        private String picture;
    }
}